package com.besttone.util;
import java.io.UnsupportedEncodingException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Map;
import java.util.TreeMap;
import java.util.Map.Entry;
import com.jfinal.kit.StrKit;
/**
 * Created by zhengzhenzhen on 2017/3/1.
 */
public class MD5Util {
    private static String encodingCharset = "UTF-8";

    /**
     * MD5加密（混淆）
     *
     * @param str 需要加密的字符串
     * @return String 加密后的字符串
     */
    public static String encrypt(String str){
        char str2[] = new char[16 * 2];
        try {
            char hexDigits[] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
                    'a', 'b', 'c', 'd', 'e', 'f' };
            MessageDigest mdt = java.security.MessageDigest.getInstance("MD5");
            mdt.update(str.getBytes());
            byte tmp[] = mdt.digest();
            int k = 0;
            for (int i = 0; i < 16; i++) {
                byte byte0 = tmp[i];
                str2[k++] = hexDigits[byte0 >>> 4 & 0xf];
                str2[k++] = hexDigits[byte0 & 0xf];
            }
        } catch (Exception e) {
            throw new RuntimeException("MD5混淆出错。");
        }
        return new String(str2).toUpperCase();
    }

    /**
     * MD5加密（标准）转大写
     *
     * @param str 需要加密的字符串
     * @return String 加密后的字符串
     */
    public static String md5UpperCase(String str){
        return commonEncrypt(str, "MD5",true);
    }
    /**
     * MD5加密（标准）
     *
     * @param str 需要加密的字符串
     * @return String 加密后的字符串
     */
    public static String md5(String str){
        return commonEncrypt(str, "MD5",false);
    }
    /**
     * SHA1加密
     *
     * @param str 需要加密的字符串
     * @return String 加密后的字符串
     */
    public static String sha1(String str){
        return commonEncrypt(str, "SHA",true);
    }

    /**
     * 加密
     *
     * @param str          加密字符串
     * @param instanceType 加密类型
     * @param UpperCase    是否转化为大写
     * @return String
     */
    private static String commonEncrypt(String str, String instanceType,boolean UpperCase){
        str = str.trim();
        byte value[];
        try {
            value = str.getBytes(encodingCharset);
        } catch (UnsupportedEncodingException e) {
            value = str.getBytes();
        }
        MessageDigest md = null;
        try {
            md = MessageDigest.getInstance(instanceType);
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
            return null;
        }
        if(UpperCase){
            return toHex(md.digest(value)).toUpperCase();
        }
        return toHex(md.digest(value));
    }

    /**
     * 十六进制转换
     *
     * @param input
     * @return String
     */
    private static String toHex(byte input[]) {
        if (input == null)
            return null;
        StringBuffer output = new StringBuffer(input.length * 2);
        for (int i = 0; i < input.length; i++) {
            int current = input[i] & 0xff;
            if (current < 16)
                output.append("0");
            output.append(Integer.toString(current, 16));
        }

        return output.toString();
    }


    public static String getMD5(byte[] source) {
        String s = null;
        char hexDigits[] = { // 用来将字节转换成 16 进制表示的字符
                '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' };
        try {
            java.security.MessageDigest md = java.security.MessageDigest.getInstance("MD5");
            md.update(source);
            byte tmp[] = md.digest(); // MD5 的计算结果是一个 128 位的长整数，
            // 用字节表示就是 16 个字节
            char str[] = new char[16 * 2]; // 每个字节用 16 进制表示的话，使用两个字符，
            // 所以表示成 16 进制需要 32 个字符
            int k = 0; // 表示转换结果中对应的字符位置
            for (int i = 0; i < 16; i++) { // 从第一个字节开始，对 MD5 的每一个字节
                // 转换成 16 进制字符的转换
                byte byte0 = tmp[i]; // 取第 i 个字节
                str[k++] = hexDigits[byte0 >>> 4 & 0xf]; // 取字节中高 4 位的数字转换,
                // >>>
                // 为逻辑右移，将符号位一起右移
                str[k++] = hexDigits[byte0 & 0xf]; // 取字节中低 4 位的数字转换
            }
            s = new String(str); // 换后的结果转换为字符串

        } catch (Exception e) {
            e.printStackTrace();
        }
        return s;
    }

    public static String sign(String key) {
        String md5KeyValue = MD5Util.encrypt(key);
        return md5KeyValue.substring(8, md5KeyValue.length() - 8);
    }

    /**
     * 将除sign以外的请求参数（包括标准参数，除非有特别说明）按照参数名称的字典升序排列，然后按此顺序，将”参数名＝参数值”用”&”符号连接
     * @param params
     * @return
     */
    public static String packageSign(Map<String, String> params) {
        // 先将参数以其参数名的字典序升序进行排序
        TreeMap<String, String> sortedParams = new TreeMap<String, String>(params);
        // 去除参与的参数sign
        sortedParams.remove("sign");
        // 遍历排序后的字典，将所有参数按"key=value"格式拼接在一起
        StringBuilder sb = new StringBuilder();
        boolean first = true;
        for (Entry<String, String> param : sortedParams.entrySet()) {
            String value = param.getValue();
            if (StrKit.isBlank(value)) {
                continue;
            }
            if (first) {
                first = false;
            } else {
                sb.append("&");
            }
            sb.append(param.getKey()).append("=");
            sb.append(value);
        }
        return sb.toString();
    }

    public static void main(String[] args) {
        String key = "jx_65432015041402120906873";
        String md5KeyValue = MD5Util.encrypt(key);
        String signKey = md5KeyValue.substring(8, md5KeyValue.length() - 8);
        System.out.println( signKey);
    }

}
